using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Roslyn.Compilers.CSharp;

namespace ContentOverContainer.Common.Converter
{
    public static class DeclarationSyntaxConverter
    {
        /// <summary>
        /// Changes the type of the field to the multiplicity type. //R-VDECL
        /// </summary>
        /// <param name="pFieldNode">The field declaration node.</param>
        /// <param name="pMultiInfo">The multiplicity info.</param>
        /// <returns></returns>
        /// <author>
        /// Harald Binkle
        /// </author>
        public static FieldDeclarationSyntax ChangeToMultiplicityType(this FieldDeclarationSyntax pFieldNode, MultiplicityInfo pMultiInfo)
        {
            if (pMultiInfo.Kind != MultiplicityKind.Any) //option case
                return pFieldNode;

            var orgType = pFieldNode.Declaration.Type;
            orgType.CheckDestMultipliciyType(pMultiInfo.Kind, pMultiInfo.Type);

            //convert type
            VariableDeclarationSyntax newDecl = pFieldNode.Declaration.WithType(pMultiInfo.Type);
            FieldDeclarationSyntax newField = pFieldNode.WithDeclaration(newDecl);

            //TODO: what if the field is already inititialized should we add that value in the class constructor? (e.g. private string m_Inited = "Inited";)
            EqualsValueClauseSyntax oldInitializer = newField.Declaration.Variables[0].Initializer;

            //Build up the initializer site  
            ExpressionSyntax initializerExpression;
            if (oldInitializer != null)
                initializerExpression = Syntax.ParseExpression(string.Format(" new {0}(){{{1}}}", pMultiInfo.Type.ToString(), oldInitializer.Value.ToString()));
            else
                initializerExpression = Syntax.ParseExpression(string.Format(" new {0}()", pMultiInfo.Type.ToString()));
            EqualsValueClauseSyntax newInitializer = Syntax.EqualsValueClause(initializerExpression);
            VariableDeclaratorSyntax decleratorSyntax = newField.Declaration.Variables[0].WithInitializer(newInitializer);
            SeparatedSyntaxList<VariableDeclaratorSyntax> decleratorSyntaxes = new SeparatedSyntaxList<VariableDeclaratorSyntax>();
            decleratorSyntaxes = decleratorSyntaxes.Add(decleratorSyntax);
            VariableDeclarationSyntax variableDecleration = newField.Declaration.WithVariables(decleratorSyntaxes);
            newField = newField.WithDeclaration(variableDecleration);

            return pFieldNode.WithDeclaration(newField.Declaration);
        }


        /// <summary>
        /// Changes the type of the proerpty to the multiplicity type.
        /// </summary>
        /// <param name="pPropNode">The property node.</param>
        /// <param name="pNewType">New multiplicity type</param>
        /// <returns></returns>
        /// <author>Harald Binkle</author>
        /// <exception cref="System.ArgumentException">
        /// The generic type does only have one argument.;pNewType
        /// or
        /// pNewType
        /// </exception>
        public static PropertyDeclarationSyntax ChangeToMultiplicityType(this PropertyDeclarationSyntax pPropNode, TypeSyntax pNewType)
        {
            pPropNode.Type.CheckDestMultipliciyType(pNewType);
            return pPropNode.WithType(pNewType);
        }

        /// <summary>
        /// Changes the type of the return type to multiplicity.
        /// </summary>
        /// <param name="pMethodNode">The p method node.</param>
        /// <param name="pNewType">New type of the p.</param>
        /// <returns></returns>
        /// <author>Harald Binkle</author>
        public static MethodDeclarationSyntax ChangeReturnTypeToMultiplicityType(this MethodDeclarationSyntax pMethodNode, TypeSyntax pNewType)
        {
            pMethodNode.ReturnType.CheckDestMultipliciyType(pNewType);
            return pMethodNode.WithReturnType(pNewType);
        }


        /// <summary>
        /// Changes the type of to multiplicity.
        /// </summary>
        /// <param name="pParameterSyn">The p parameter syn.</param>
        /// <param name="pNewType">New type of the p.</param>
        /// <returns></returns>
        /// <author>Harald Binkle</author>
        public static ParameterSyntax ChangeToMultiplicityType(this ParameterSyntax pParameterSyn, TypeSyntax pNewType)
        {
            pParameterSyn.Type.CheckDestMultipliciyType(pNewType);
            return pParameterSyn.WithType(pNewType);
        }



    }
}
